package com.zjb.demo.system.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.mybatisflex.core.paginate.Page;
import com.zjb.demo.common.domain.dto.SysLoginInfo;
import com.zjb.demo.common.domain.response.AjaxResult;
import com.zjb.demo.common.exception.ServiceException;
import com.zjb.demo.common.util.SecurityUtils;
import com.zjb.demo.system.domain.SysRole;
import com.zjb.demo.system.domain.SysUserRole;
import com.zjb.demo.system.domain.User;
import com.zjb.demo.system.domain.query.SysRoleQuery;
import com.zjb.demo.system.domain.query.UserQuery;
import com.zjb.demo.system.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.noear.solon.annotation.*;
import org.noear.solon.core.handle.Context;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 庄佳彬
 * @since 2023/12/31 10:47
 */
@Controller
@Mapping("/system/role")
@Api(tags = "系统：角色管理")
public class SysRoleController {

    @Inject
    private SysRoleService roleService;
    @Inject
    private TokenService tokenService;
    @Inject
    private SysPermissionService permissionService;

    @Inject
    private UserService userService;

    @Inject
    private SysDeptService deptService;

    @Get
    @Mapping("/list")
    @ApiOperation(value = "分页查询角色")
    public AjaxResult<Page<SysRole>> list(SysRoleQuery query) {
        return AjaxResult.success(roleService.pageList(query));

    }

    @Get
    @Mapping("/export")
    @ApiOperation(value = "导出角色")
    public void export(SysRoleQuery query) throws IOException {
        var list = roleService.list(query);
        var ctx = Context.current();
        ctx.contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        ctx.headerAdd("Content-Disposition", "attachment;filename=" + URLEncoder.encode("导出角色", StandardCharsets.UTF_8) + DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx");
        var os = ctx.outputStream();
        EasyExcel.write(os, SysLoginInfo.class)
                .sheet("导出角色")
                .doWrite(list);
    }

    @Get
    @Mapping("/{roleId}")
    @ApiOperation(value = "查询角色")
    public AjaxResult<SysRole> get(Long roleId) {
        return AjaxResult.success(roleService.getById(roleId));
    }

    @Post
    @Mapping
    @ApiOperation(value = "新增角色")
    public AjaxResult<Boolean> save(SysRole role) {
        if (roleService.existsRoleName(role.getRoleName())) {
            return AjaxResult.fail("角色名称已存在");
        }
        if (roleService.existsRoleKey(role.getRoleName())) {
            return AjaxResult.fail("角色权限已存在");
        }

        return AjaxResult.success(roleService.save(role));
    }

    @Put
    @Mapping
    @ApiOperation(value = "修改角色")
    public AjaxResult<Boolean> update(@Body SysRole role) {
        checkRoleAllow(role.getRoleId());
        roleService.checkRoleDateScope(role.getRoleId());
        if (roleService.existsRoleName(role.getRoleName())) {
            return AjaxResult.fail("角色名称已存在");
        }
        if (roleService.existsRoleKey(role.getRoleName())) {
            return AjaxResult.fail("角色权限已存在");
        }
        if (roleService.updateById(role)) {
            tokenService.setLoginUser(() -> SecurityUtils.getLoginUser()
                    .filter(it -> !SecurityUtils.isAdmin())
                    .map(loginUser -> {
                        loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
                        userService.selectUserByUserName(loginUser.getUsername())
                                .ifPresent(loginUser::setUser);
                        return loginUser;
                    })
            );
        }

        return AjaxResult.fail("修改角色'" + role.getRoleName() + "'失败，请联系管理员");
    }

    @Put
    @Mapping("/changeStatus")
    @ApiOperation(value = "修改角色状态")
    public AjaxResult<Boolean> changeStatus(@Body SysRole role) {
        checkRoleAllow(role.getRoleId());
        roleService.checkRoleDateScope(role.getRoleId());
        return AjaxResult.success(roleService.updateStatusById(role.getStatus(), role.getRoleId()));
    }

    @Delete
    @Mapping("/{roleIds}")
    @ApiOperation(value = "删除角色")
    public AjaxResult<Boolean> delete(Long[] roleIds) {
        var list = List.of(roleIds);
        list.forEach(id -> {
            checkRoleAllow(id);
            roleService.checkRoleDateScope(id);
        });
        if (roleService.countRoleByRoleIds(list) > 0) {
            return AjaxResult.fail("存在已分配,不能删除");
        }
        return AjaxResult.success(roleService.removeByIds(roleIds));
    }

    @Get
    @Mapping("/optionselect")
    @ApiOperation(value = "查询角色")
    public AjaxResult<List<SysRole>> optionselect() {
        return AjaxResult.success(roleService.list());
    }

    @Get
    @Mapping("/authUser/allocatedList")
    @ApiOperation(value = "查询已分配用户角色")
    public AjaxResult<Page<User>> allocatedList(UserQuery query) {
        return AjaxResult.success(userService.selectAllocatedList(query));
    }

    @Get
    @Mapping("/authUser/unallocatedList")
    @ApiOperation(value = "查询未分配用户角色")
    public AjaxResult<Page<User>> unallocatedList(UserQuery query) {
        return AjaxResult.success(userService.selectUnallocatedList(query));
    }

    @Put
    @Mapping("/authUser/cancel")
    @ApiOperation(value = "取消授权")
    public AjaxResult<Boolean> cancel(@Body SysUserRole userRole) {
        return AjaxResult.success(roleService.deleteAuthUser(userRole));
    }

    @Put
    @Mapping("/authUser/cancelAll")
    @ApiOperation(value = "批量取消授权")
    public AjaxResult<Boolean> cancelAll(Long roleId, Long[] userIds) {
        return AjaxResult.success(roleService.deleteAuthUsers(roleId, userIds));
    }

    @Put
    @Mapping("/authUser/selectAll")
    @ApiOperation(value = "批量选择用户授权")
    public AjaxResult<Boolean> selectAuthUserAll(Long roleId, Long[] userIds) {
        roleService.checkRoleDateScope(roleId);
        return AjaxResult.success(roleService.insertAuthUsers(roleId, userIds));
    }

    @Get
    @Mapping("/deptTree/{roleId}")
    @ApiOperation(value = "获取对应角色部门树列表")
    public AjaxResult<Map<String, Object>> deptTree(Long roleId) {
        var result = new HashMap<String, Object>();
        result.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
        result.put("depts", deptService.selectDeptTreeList());
        return AjaxResult.success(result);
    }


    /**
     * 检查角色是否允许
     *
     * @param roleId 角色ID
     * @throws ServiceException 如果角色不允许则抛出
     */
    private void checkRoleAllow(Long roleId) {
        if (roleId != null && roleId == 1L) {
            throw new ServiceException("超级管理员角色不允许删除");
        }
    }

}
